package com.yy.hi.ui.refresh;

import android.content.Context;
import android.content.IntentFilter;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
import android.widget.Scroller;

import com.yy.hi.ui.refresh.util.HiScrollUtil;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public class HiRefreshLayout extends FrameLayout implements HiRefresh {
    private HiOverView.HiRefreshState mState;
    private GestureDetector mGestureDetector;
    private HiRefreshListener mHiRefreshListener;
    protected HiOverView mHiOverView;
    private int mLastY;
    private boolean disableRefreshScroll;
    private AutoScroller mAutoScroller;

    public HiRefreshLayout(@NonNull Context context) {
        this(context, null);
    }

    public HiRefreshLayout(@NonNull Context context,
                           @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public HiRefreshLayout(@NonNull Context context, @Nullable AttributeSet attrs,
                           int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public void init() {
        mGestureDetector = new GestureDetector(getContext(), mHiGestureDetector);
        mAutoScroller = new AutoScroller();
    }

    @Override
    public void setDisableRefreshScroll(boolean disableRefreshScroll) {
        this.disableRefreshScroll = disableRefreshScroll;
    }

    @Override
    public void refreshFinished() {
        View header = getChildAt(0);
        mHiOverView.onFinish();
        mHiOverView.setRefreshState(HiOverView.HiRefreshState.STATE_INIT);
        int bottom = header.getBottom();
        if (bottom > 0) {
            recover(bottom);
        }
        mState = HiOverView.HiRefreshState.STATE_INIT;
    }

    @Override
    public void setRefreshListener(HiRefreshListener listener) {
        this.mHiRefreshListener = listener;
    }

    @Override
    public void setRefreshOverView(HiOverView hiOverView) {
        this.mHiOverView = hiOverView;
    }

    HiGestureDetector mHiGestureDetector = new HiGestureDetector() {
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            if (Math.abs(distanceX) > Math.abs(distanceY) ||
                    mHiRefreshListener != null && !mHiRefreshListener.enableRefresh()) {
                return false;
            }
            //刷新时禁止滚动
            if (disableRefreshScroll && mState == HiOverView.HiRefreshState.STATE_REFRESH) {
                return true;
            }
            View header = getChildAt(0);
            View child = HiScrollUtil.findScrollableChild(HiRefreshLayout.this);
            if (HiScrollUtil.childScrolled(child)) {
                return false;
            }
            //没有刷新或者没有达到下拉刷新的高度,且头部已经拉出来了
            if (mState != HiOverView.HiRefreshState.STATE_REFRESH ||
                    header.getBottom() <= mHiOverView.mPullRefreshHeight &&
                            (header.getBottom() > 0 || distanceY <= 0.0f)) {
                //还在滑动中
                if (mState != HiOverView.HiRefreshState.STATE_REFRESH) {
                    int seed;
                    //速度计算
                    if (child.getTop() < mHiOverView.mPullRefreshHeight) {
                        seed = (int) (mLastY / mHiOverView.minDamp);
                    } else {
                        seed = (int) (mLastY / mHiOverView.maxDamp);
                    }

                    boolean bool = moveDown(seed, true);
                    mLastY = (int) -distanceY;
                    return bool;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }
    };

    private boolean moveDown(int offsetY, boolean nonAuto) {
        View head = getChildAt(0);
        View child = getChildAt(1);
        int childTop = child.getTop() + offsetY;
        if (childTop <= 0) {
            offsetY = -child.getTop();
            head.offsetTopAndBottom(offsetY);
            child.offsetTopAndBottom(offsetY);
            if (mState != HiOverView.HiRefreshState.STATE_REFRESH) {
                mState = HiOverView.HiRefreshState.STATE_INIT;
            }
        } else if (mState == HiOverView.HiRefreshState.STATE_REFRESH &&
                childTop > mHiOverView.mPullRefreshHeight) {
            //正在下拉刷新
            refresh();
            return false;
        } else if (childTop <= mHiOverView.mPullRefreshHeight) {
            if (mHiOverView.getRefreshState() != HiOverView.HiRefreshState.STATE_VISIBLE &&
                    nonAuto) {
                mHiOverView.onVisible();
                mHiOverView.setRefreshState(HiOverView.HiRefreshState.STATE_VISIBLE);
                mState = HiOverView.HiRefreshState.STATE_VISIBLE;
            }
            head.offsetTopAndBottom(offsetY);
            child.offsetTopAndBottom(offsetY);
            if (childTop == mHiOverView.mPullRefreshHeight &&
                    mState == HiOverView.HiRefreshState.STATE_OVER_RELEASE) {
                //下拉刷新完成
            }
        } else {
            if (mHiOverView.getRefreshState() != HiOverView.HiRefreshState.STATE_OVER && nonAuto) {
                //超出刷新位置
                mHiOverView.onOver();
                mHiOverView.setRefreshState(HiOverView.HiRefreshState.STATE_OVER);
            }
            head.offsetTopAndBottom(offsetY);
            child.offsetTopAndBottom(offsetY);
        }
        if (mHiOverView != null) {
            mHiOverView.onScroll(head.getBottom(), mHiOverView.mPullRefreshHeight);
        }
        return true;
    }

    private void refresh() {
        if (mHiRefreshListener != null) {
            mState = HiOverView.HiRefreshState.STATE_REFRESH;
            mHiOverView.onRefresh();
            mHiOverView.setRefreshState(HiOverView.HiRefreshState.STATE_REFRESH);
            mHiRefreshListener.onRefresh();
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        View header = getChildAt(0);
        if (ev.getAction() == MotionEvent.ACTION_UP ||
                ev.getAction() == MotionEvent.ACTION_CANCEL ||
                ev.getAction() == MotionEvent.ACTION_POINTER_INDEX_MASK) {
            // header被拉下来
            if (header.getBottom() > 0) {
                //没有达到下拉刷新的高度
                if (mState != HiOverView.HiRefreshState.STATE_REFRESH) {
                    recover(header.getBottom());
                    return false;
                }
            }
            mLastY = 0;
        }
        boolean consumed = mGestureDetector.onTouchEvent(ev);
        if (consumed || (mState != HiOverView.HiRefreshState.STATE_INIT &&
                mState != HiOverView.HiRefreshState.STATE_REFRESH && header.getBottom() > 0)) {
            // 父类不接受事件
            ev.setAction(MotionEvent.ACTION_CANCEL);
        }
        return super.dispatchTouchEvent(ev);
    }

    private void recover(int distance) {
        if (mHiRefreshListener != null && distance > mHiOverView.mPullRefreshHeight) {
            //滚动指定位置  dis-mHiOverView.mPullRefreshHeight
            mAutoScroller.recover(distance - mHiOverView.mPullRefreshHeight);
            mState = HiOverView.HiRefreshState.STATE_REFRESH;
        } else {
            mAutoScroller.recover(distance);
        }
    }

    private class AutoScroller implements Runnable {
        private Scroller mScroller;
        private int mLastY;
        private boolean mIsFinished;

        public AutoScroller() {
            mScroller = new Scroller(getContext(), new LinearInterpolator());
            mIsFinished = true;
        }

        @Override
        public void run() {
            if (mScroller.computeScrollOffset()) {
                moveDown(mLastY - mScroller.getCurrY(), false);
                mLastY = mScroller.getCurrY();
                post(this);
            } else {
                removeCallbacks(this);
                mIsFinished = true;
            }
        }

        void recover(int dis) {
            if (dis < 0) {
                return;
            }
            removeCallbacks(this);
            mLastY = 0;
            mIsFinished = false;
            mScroller.startScroll(0, 0, 0, dis, 300);
            post(this);
        }

        boolean isFinished() {
            return mIsFinished;
        }
    }
}
